package org.caenv.interpreter;

import java.io.IOException;
import org.caenv.interpreter.parser.ParserXMLHandler;
import org.caenv.interpreter.pojo.instructions.ExecutionPlan;
import org.caenv.interpreter.pojo.instructions.Instruction;
import org.caenv.interpreter.pojo.instructions.State;
import org.caenv.interpreter.util.SourceUtils;
import org.xml.sax.SAXException;

public class Interpreter {

    private final ExecutionPlan executionPlan;
    private final ProgramTO programTO;

    public Interpreter(ProgramTO program) {
        this.executionPlan = new ExecutionPlan();
        this.programTO = program;
    }

    public void execute() throws ExecutionException {

        try {

            /*
             * Parse the code
             */
            ParserXMLHandler parserXMLHandler = new ParserXMLHandler(executionPlan, SourceUtils.generateInputSourceByString(this.programTO.getCodes()));
            parserXMLHandler.parse();
            
            /*
             * Variables
             */
            for(String variable : this.programTO.getVariables()){
                this.executionPlan.getMemoryManager().addVariable(variable, null); 
            }
            
            /*
             * Change the first state
             */
            executionPlan.setStateByName(this.programTO.getFirstState());
            
            /*
             * Execute the program
             */
            for (State state = this.executionPlan.getCurrentState(); state != null; state = this.executionPlan.getCurrentState()) {

                System.out.println("Executando estado: " + state.getName());
                
                state.initializeState();

                for (Instruction instruction = state.nextInstruction(); instruction != null; instruction = state.nextInstruction()) {
                    System.out.println("Executando instrucao: " + instruction.getClass().getSimpleName());
                    instruction.execute(executionPlan);
                }
            }

        } catch (SAXException ex) {
            throw new ExecutionException(ex);
        } catch (IOException ex) {
            throw new ExecutionException(ex);
        }

    }
}
